using System;
using System.Collections.Generic;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using NTrace;

namespace NTrace.Tasks
{
    public class ClearIntermediateFiles : Task
    {
        private Guid providerId;
        private String outputFolder;

        private struct FileCacheEntry
        {
            public String CacheName;
            public String OriginalName;
            public DateTime OriginalDate;
        }

        public ClearIntermediateFiles()
        {
        }

        [Required]
        public String ProviderId
        {
            get
            {
                return this.providerId.ToString("D");
            }
            set
            {
                this.providerId = new Guid(value);
            }
        }

        [Required]
        public ITaskItem[] Sources { get; set; }

        [Required]
        public String OutputFolder
        {
            get
            {
                return this.outputFolder;
            }
            set
            {
                this.outputFolder = value;
            }
        }

        public override bool Execute()
        {
            try
            {
                IDictionary<String, FileCacheEntry> cachedFiles = new Dictionary<String, FileCacheEntry>();
                for (int itemIndex = 0; itemIndex < this.Sources.Length; itemIndex++)
                {
                    FileCacheEntry entry = new FileCacheEntry();
                    System.IO.FileInfo fileInfo = new System.IO.FileInfo(this.Sources[itemIndex].ItemSpec);
                    entry.OriginalName = fileInfo.FullName;
                    entry.OriginalDate = fileInfo.LastWriteTime;
                    entry.CacheName = FileProcessor.GetCachedFileName(this.OutputFolder, entry.OriginalName);
                    cachedFiles[entry.CacheName.ToLowerInvariant()] = entry;
                }

                System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(this.OutputFolder);
                System.IO.FileInfo[] files = di.GetFiles();
                
                System.Text.RegularExpressions.Regex messageGuidExtractor = new System.Text.RegularExpressions.Regex(
                    "_etwMessageGuid = new System\\.Guid\\(\"(?<guid>[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12})\"\\)",
                    System.Text.RegularExpressions.RegexOptions.Compiled);

                System.Collections.Generic.IDictionary<String, bool> filesToKeep = new System.Collections.Generic.Dictionary<String, bool>();
                String controlGuidFilePath = System.IO.Path.Combine(this.OutputFolder, this.ProviderId + ".ctl");
                filesToKeep[controlGuidFilePath.ToLowerInvariant()] = true;

                String traceMessageControlFilePath = System.IO.Path.Combine(this.OutputFolder, this.ProviderId + ".tmc");
                filesToKeep[traceMessageControlFilePath.ToLowerInvariant()] = true;

                for (int index = 0; index < files.Length; index++)
                {
                    FileCacheEntry entry;
                    // If we do not have a matching file in the cache with a write date < this file's date, delete this file.
                    if (cachedFiles.TryGetValue(files[index].FullName.ToLowerInvariant(), out entry))
                    {
                        if (entry.OriginalDate <= files[index].LastWriteTime)
                        {
                            filesToKeep[files[index].FullName.ToLowerInvariant()] = true;

                            String contents;
                            using (System.IO.TextReader reader = new System.IO.StreamReader(entry.CacheName))
                            {
                                contents = reader.ReadToEnd();
                            }

                            System.Text.RegularExpressions.Match match = messageGuidExtractor.Match(contents);
                            if (match.Success)
                            {
                                String tmfName = match.Groups["guid"].Value + ".tmf";
                                String tmfPath = System.IO.Path.Combine(this.OutputFolder, tmfName);
                                filesToKeep[tmfPath.ToLowerInvariant()] = true;
                            }
                        }
                    }
                }

                for (int index = 0; index < files.Length; index++)
                {
                    if (filesToKeep.ContainsKey(files[index].FullName.ToLowerInvariant()))
                    {
                        this.Log.LogMessage(MessageImportance.Normal, "Preserving intermediate file '{0}'...", files[index].FullName);
                        continue;
                    }

                    this.Log.LogMessage(MessageImportance.Normal, "Deleting intermediate file '{0}'...", files[index].FullName);
                    try
                    {
                        files[index].Delete();
                    }
                    catch (System.IO.IOException e)
                    {
                        this.Log.LogMessage(MessageImportance.Low, "Unable to delete file '{0}': {1}", files[index].FullName, e);
                    }
                }
            }
            catch (System.IO.IOException e)
            {
                this.Log.LogMessage(MessageImportance.Low, "Unable to delete files from directory '{0}': {1}", this.OutputFolder, e);
            }

            return true;
        }
    }
}
